샘플
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr" />
<title>DOM API를 사용한 HTML 문서 접근</title>
<script type="text/javascript">
window.onload = function() {
var roodNode = document.documentElement;
log("root 태그: "+roodNode.tagName); var bodyNode = document.getElementsByTagName("body").item(0);
log("body 태그: "+bodyNode.tagName);
var spanList = document.getElementsByTagName("span");
log("span 태그의 개수: "+spanList.length);
for (var i = 0 ; i < spanList.length ; i++)
{ var span = spanList.item(i); log((i+1)+"번째 span의 id : "+span.getAttribute("id")); }
?
var debugConsoleDiv = document.getElementById("debugConsole");
log("debugConsole 요소: "+debugConsoleDiv.tagName);
var bodyLastChild = bodyNode.lastChild;
log("body의 마지막 자식 노드: "+bodyLastChild.nodeName);
}
function log(msg) {
var console = document.getElementById("debugConsole");
if (console != null)
{ console.innerHTML += msg +" "; }}
</script>
</head>
<body>
<SPAN id="a">a</SPAN>
<p>test<span id="b">b</span></p>
<div><p>p</p><span id="c">c</span></div>
<div id="debugConsole" style="border: 1px solid #000"></div>
</body>
</html>
샘플
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ko" lang="ko">
<head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr" />
<title>DOM을 사용한 변경</title>
<script type="text/javascript">
var count = 0;
function appendItem() { count++; var newItem = document.createElement("div"); newItem.setAttribute("id", "item_" + count);
var html = '새로 추가된 아이템['+count+']'+ ''; newItem.innerHTML = html;
var itemListNode = document.getElementById('itemList'); itemListNode.appendChild(newItem); }function removeItem(idCount) {
var item = document.getElementById("item_"+idCount);
if (item != null)
{ item.parentNode.removeChild(item); }}
</script>
</head>
<body>
<input type='button' value='추가' onclick='appendItem()' />
<div id="itemList"></div>
</body>
</html>
문서 객체 모델(DOM; Document Object Model)은 HTML내에 들어 있는 요소를 구조화 객체 모델로 표현하는 형식이다.
DOM은 플랫폼/언어 중립적으로 구조화된 문서를 표현하는 W3C 표준 모델이 기반이 된다.
객체 접근 방법
?function getObject(objectId) {
if(document.getElementById && document.getElementById(objectId)
{ return document.getElementById(objectId); // check W3C DOM }
else if (document.all && document.all(objectID)
{ return document.all(objectID); // IE4 }
else if (document.layers && document.layersobjectID
{ return document.layer\[objectID\]; // NN4 }
else
{ return false; }
}
위의 스크립트를 통해 getObject(objectId)를 이용하여 모든 브라우저의 DOM 객체를 얻을 수 있다.
객체 사용 방법
DOM객체와 노드 및 그 속성을 조작 하는 방법은 일반적인 W3C DOM 표준을 따른다.
createElement(), createTextNode() 같은 노드 생성 및 접근, nodeName, nodeType,tagName 같은 노드 정보, childNode, firstChild같은 트리 구조 파악 등은 비교적 표준
이 잘 지켜 지고 있다.
그러나, getAttribute(), removeAttribute() 같은 속성 정의 인터페이스들은 브라우저 마다 다른 점이 매우 많아서 사용에 주의를 요한다. 이러한 차이점은 부록에 나와 있는 DOM 브라우저 호환 차트를 참고해야 한다.
객체 요소를 다루는 메소드에 있어서도 IE에서만 사용되는 MS DOM 확장 메소드들이 있다. 이들에 대해서도 사용에 주의를 요하며 이를 대체할 수 있는 W3C DOM을 사용한다.
윈도우 위치 파악
DOM을 사용하다 보면 윈도우 위에 각종 DOM 레이어들을 배치 시키고 위치를 잡도록 해야될 필요가 있다.
크기와 높이 위치를 정하는 방식이 다르기 때문에 이에 대한 호환 방식을 알아둘 필요가 있다.
Inner width알기
?var x,y;
if (self.innerHeight)
{ // IE 외 모든 브라우저 x = self.innerWidth; y = self.innerHeight; }
else if (document.documentElement &&
document.documentElement.clientHeight)
{ // Explorer 6 Strict 모드 x = document.documentElement.clientWidth; y = document.documentElement.clientHeight; }
else if (document.body)
{ // 다른 IE 브라우저 x = document.body.clientWidth; y = document.body.clientHeight; }
스크롤 위치 파악
var x,y;
if (self.pageYOffset)
{ // IE 외 모든 브라우저 x = self.pageXOffset; y = self.pageYOffset; }
else if (document.documentElement &&
document.documentElement.scrollTop)
{ // Explorer 6 Strict x = document.documentElement.scrollLeft; y = document.documentElement.scrollTop; }
else if (document.body)
{ // IE 브라우저 x = document.body.scrollLeft; y = document.body.scrollTop; }
스타일 가져오기
MS에서는 x.currentStyle이라는 메소드를 지원하지만 W3C에서는 getComputedStyle()을 사용하므로 브라우저간 호환성 문제가 생긴다.
#test
{font-size: 16px; padding: 10px; width: 50%; border-width: 1px; border-style: solid; border-color: #cc0000; }
위와 같은 test라는 클래스의 font-size 속성을 읽어 오려면 다음과 같이 한다
testProp=getStyle("test","width");
function getStyle(el,styleProp)
{ var x = document.getElementById(el);
if (x.currentStyle)
var y = x.currentStyle\[styleProp\];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(style Prop);
return y; }
x.style.pixelLeft = x; // IE4/5
x.style.pixelTop = y; // IE4/5
x.style.left = value + "px"; // DOM Level 2
x.style.top = value + "px"; // DOM Level2
W3C DOM 방식과 HTML 테이블 DOM 방식, innerHTML 방식을 비교하여 실험해 본 결과 innerHTML의 성능이 가장 빠른 것을 알 수 있다
<script type="text/javascript">
function handleEvent(aEvent)
{ // aEvent 가 null 이면 IE 이기 때문에 window.event 를 반환한다.
var myEvent = aEvent ? aEvent : window.event; }
</script>
<div onclick="handleEvent(event)">Click me!</div>
브라우저 호환 이벤트 캐칭을 위해서는 위의 스크립트가 항상 초기화 되어 있어야 한다.
표준 지원에 대한 범위가 다르므로 아래와 같은 코드로 마우스의 위치를 파악한다.
function getPosition(e)
{
var posx = 0;
var posy = 0;
if (!e) var e = window.event; // 이벤트 검사
if (e.pageX || e.pageY)
{ // pageX/Y 표준 검사 posx = e.pageX; posy = e.pageY; }
else if (e.clientX || e.clientY) { //clientX/Y 표준 검사 Opera
posx = e.clientX;
posy = e.clientY;
if (isIE)
{ // IE 여부 검사 posx \+= document.body.scrollLeft; posy \+= document.body.scrollTop; }
}
}
이벤트 핸들러 등록
MS DOM 및 W3C DOM 지원 브라우저 간에 완전히 다른 이벤트 핸들러 인터페이스를 가지고 있다.
양쪽을 모두 지원할 수 있는 attachEvent 판별 스크립트는 아래와 같다.
function attachEvent (obj, evt, fuc, useCapture) {
if(!useCapture) useCapture=false;
if(obj.addEventListener)
{ // W3C DOM 지원 브라우저 return obj.addEventListener(evt,fuc,useCapture); }
else if(obj.attachEvent)
{ // MSDOM 지원 브라우저 return obj.attachEvent("on"+evt, fnc); }
else { // NN4 나 IE5mac 등 비 호환 브라우저
MyAttachEvent(obj, evt, fnc);
obj['on'+evt]=function()
{ MyFireEvent(obj,evt) }
;
}
}
function MyAttachEvent(obj, evt, fuc) {
if(!obj.myEvents) obj.myEvents= {};
if(!obj.myEvents[evt]) obj.myEvents[evt]=[];
var evts = obj.myEvents[evt];
evts[evts.length]=fnc;
}
function MyFireEvent(obj, evt)
{ if(\!obj )}
!obj.myEvents || !obj.myEvents[evt]) return;
var evts = obj.myEvents[evt];
for (var i=0;len=evts.length; i<len;i++) evts[i]();
}
표준 DOM에서 XML을 처리하는 방법을 알아보고자 한다.
XML 데이터 핸들링
//XML:
<?xml version="1.0"?>
<myXMLdoc xmlns:myns="http://myfoo.com">
<myns:foo>bar</myns:foo>
</myXMLdoc>
// JavaScript:
var myXMLDoc = getXMLDocument().documentElement;
alert(myXMLDoc.childNodes.length);
위의 예제에서 documentElement를 통해 myXMLDoc에 XML 문서를 로드한 후에 이를 표시하는 내용.
이 자식 노드의 길이에서 공백을 포함하기 때문에 3이 나오지만 IE인 경우에는 1이 나오게 된다.
모든 노드는 nodeType을 가지는데, 요소 노드인 형식1과 문서 노드인 형식 9를 가질 때, 텍스트 노드를 분리해 내기 위해
텍스트 노드 형식 3과 코멘트 노드 형식 8여부를 아래와 같이 확인한다.
// XML:
<?xml version="1.0"?>
<myXMLdoc xmlns:myns="http://myfoo.com">
<myns:foo>bar</myns:foo>
</myXMLdoc>
// JavaScript:
var myXMLDoc = getXMLDocument().documentElement;
var myChildren = myXMLDoc.childNodes;
for (var run = 0; run < myChildren.length; run++){
if ( (myChildren[run].nodeType != 3) &&
(myChildren[run].nodeType != 8) )
{ // not a text or comment node }
}
XML data island 처리
IE에서는 XML data islands라는 비표준 기능이 있다.
HTML 문서내에서 XML을 임베딩 시키는 것인데 <xml>이라는 비표준 태그를 사용하며 다른 브라우저에서는 지원하지 않는다.
XHTML을 사용해서 같은 기능을 구현해 볼 수 있다.
<xml id="xmldataisland">
<foo>bar</foo>
</xml>
방법은 XML 문서를 생성하고 파싱하는 DOM 파서를 사용하는 것인데 모질라에서는 DOMParser라는 구현을 이용한다.
IE에서는 ActiveX로 된 Microsoft.XMLDOM에서 이러한 작업을 처리한다.
var xmlString = "<xml
id=\"xmldataisland\"><foo>bar</foo></xml>";
var myDocument;
if (document.implementation.createDocument)
{ // Mozilla 에서 DOMParser 를 이용한다.
var parser = new DOMParser();
myDocument = parser.parseFromString(xmlString, "text/xml"); }
else if (window.ActiveXObject)
{ // IE 에서 XMLDOM 객체를 이용한다.
myDocument = new ActiveXObject("Microsoft.XMLDOM") myDocument.async="false";
myDocument.loadXML(xmlString); }
XMLHttpRequest 처리
IE에서는 IE5.0부터 MSXML데이터를 통신으로 처리하기 위해 XMLHTTPRequest라는 객체를 ActiveX Object에 포함해서 비표준으로 제공하고 있다.
이것을 사용하기 위해서는 ActiveXObject("MSxml2.XMLHTTP) 혹은 ActiveXObject("Microsofot.XMLHTTP)라는 객체를 불러서 사용할 수 있다.
다른 브라우저에서 XMLHttpRequest라는 자바스크립트 객체로 지원하게 됨에 따라 비동기 통신 기능을 하는 표준이 되었다.
다른 명칭으로는 Ajax(Asynchronous Javascript and XML)로 불린다.
// 객체 판별
var xmlhttp = false;
if (window.XMLHttpRequest)
{ myXMLHTTPRequest = new XMLHttpRequest(); }
else
{ myXMLHTTPRequest = new ActiveXObject("Microsoft.XMLHTTP"); }
// 동기 통신 요청
myXMLHTTPRequest.open("GET", "data.xml", false);
myXMLHTTPRequest.send(null);
var myXMLDocument = myXMLHTTPRequest.responseXML;
//비동기 통신 요청
function xmlLoaded()
{ var myXMLDocument = myXMLHTTPRequest.responseXML; }
function loadXML()
{ myXMLHTTPRequest = new XMLHttpRequest();
myXMLHTTPRequest.open("GET", "data.xml", true);
myXMLHTTPRequest.onload = xmlLoaded;
myXMLHTTPRequest.send(null); }
ECMAscript vs. Jscript?
JScript는1996년 8월 인터넷 익스플로러 3.0에 포함되어 출시되었다.
넷스케이프는 표준화를 위해 자바스크립트 기술 명세를 ECMA 인터내셔널에 제출하였고, 이 명세에 대한 작업은 ECMA-262의 이름으로 1996년 11월부터 시작됐다.
ECMA-262의 초판은 ECMA 일반 회의에서 1997년 6월 채택됐다.
ECMAScript는 ECMA-262에 의해 표준화된 언어의 이름이다.
자바스크립트와 JScript는 모두 ECMA스크립트와의 호환을 목표로 하면서 ECMA 명세에 포함되지 않는 다른 확장기능을 제공한다.
{+}브라우저 스니핑{+}
대부분 객체 기반의 브라우저 판별법을 사용한다. 지원하는 브라우저에 객체모델이 존재하는지 여부를 통해 간단하게 구현 기능을 확인한다.
if (document.getElementById)
{ // NS6+, IE 5+, Opera 5\+ elm = document.getElementById(id); }
else if (document.all)
{ // IE4, Opera elm = document.all\[id\]; }
else if (document.layers)
{ // NN4 elm = document.layers\[id\]; }
W3C DOM을 사용하는 표준 웹브라우저에서 다음과 같이 <div id=xxx>...</div>로 규정된 영역을 이동하는 간단한 스크립트를 생성
function moveElement(id, x, y){ // W3C DOM Browser
var elm = document.getElementById(id);
if (elm)
{ elm.style.left = x + 'px'; elm.style.top = y + 'px'; }
}
Browser sniffing으로 불리는 이러한 방법은 흔히 ECMAScript 함수에 의해 다루어져 아래와 같은 스크립트로 브라우저의 버전과 제품 벤더를 확인할 수도 있다.
// convert all characters to lowercase to simplify testing
var agt=navigator.userAgent.toLowerCase();
// ** BROWSER VERSION **
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
var is_major = parseInt(navigator.appVersion);
var is_minor = parseFloat(navigator.appVersion);
// Note: Opera and WebTV spoof Navigator
var is_nav = ((agt.indexOf('mozilla')!=-1) &&
(agt.indexOf('spoofer')==-1)&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
var is_nav2 = (is_nav && (is_major == 2));
var is_nav3 = (is_nav && (is_major == 3));
var is_nav4 = (is_nav && (is_major == 4));
var is_nav4up = (is_nav && (is_major >= 4));
var is_navonly = (is_nav && ((agt.indexOf(";nav") != -1) ||(agt.indexOf("; nav") != -1)) );
var is_nav6 = (is_nav && (is_major == 5));
var is_nav6up = (is_nav && (is_major >= 5));
var is_gecko = (agt.indexOf('gecko') != -1);
var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera")== -1));
var is_ie3 = (is_ie && (is_major < 4));
var is_ie4 = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
var is_ie4up = (is_ie && (is_major >= 4));
var is_ie5 = (is_ie && (is_major == 4) && (agt.indexOf("msie5.0")!=-1) );
var is_ie5_5 = (is_ie && (is_major == 4) && (agt.indexOf("msie5.5") !=-1));
var is_ie5up = (is_ie && !is_ie3 && !is_ie4);
var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
var is_ie6 = (is_ie && (is_major == 4) && (agt.indexOf("msie6.")!=-1) );
var is_ie6up = (is_ie && !is_ie3 && !is_ie4 && !is_ie5&& !is_ie5_5);
// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
var is_aol = (agt.indexOf("aol") != -1);
var is_aol3 = (is_aol && is_ie3);
var is_aol4 = (is_aol && is_ie4);
var is_aol5 = (agt.indexOf("aol 5") != -1);
var is_aol6 = (agt.indexOf("aol 6") != -1);
var is_opera = (agt.indexOf("opera") != -1);
var is_opera2=(agt.indexOf("opera 2") != -1 ||agt.indexOf("opera/2") != -1);
var is_opera3=(agt.indexOf("opera 3") != -1 ||agt.indexOf("opera/3") != -1);
var is_opera4=(agt.indexOf("opera 4") != -1 ||agt.indexOf("opera/4") != -1);
var is_opera5=(agt.indexOf("opera 5") != -1 ||agt.indexOf("opera/5") != -1);
var is_opera5up=(is_opera && !is_opera2 && !is_opera3&& !is_opera4);
var is_webtv = (agt.indexOf("webtv") != -1);
var is_TVNavigator = ((agt.indexOf("navio") != -1)|| (agt.indexOf("navio_aoltv") != -1));
var is_AOLTV = is_TVNavigator;
var is_hotjava = (agt.indexOf("hotjava") != -1);
var is_hotjava3 = (is_hotjava && (is_major == 3));
var is_hotjava3up = (is_hotjava && (is_major >= 3));
일반적인 코딩 규칙
자바스크립트를 사용할 때는 <script> 태그에 language="JavaScript"를 속성으로 선언해 사용하는 경우가 있는데 반드시 type="text/javascript"를 사용해 준다
<SCRIPT type="text/javascript"><!- // // -> </SCRIPT>
<NOSCRIPT>
<UL>
<LI><A href="choice1.html" >Choice1</A></LI>
<LI><A href="choice2.html" >Choice2</A></LI>
</UL>
</NOSCRIPT>
<\!--로 시작하여 \->로 끝내고, 주석 내용 안에는 하이폰 이 두개 이상 들어가지 않도록 한다. 즉, <\!==Comment==>, <\!\- Comment \--> 방식이 바른 표현이다
getYear()의 Y2K 문제
ECMAscript Spec에 있는 getFullYear()함수를 사용한다.
속성 입력할 때 주의점
<a href="javascript:goURL(here);" >틀린 표현</a>
<a href="http://wiki.gurubee.net/pages/editpage.action#" onClick="javascript:goURL(here);">맞는 표현</a>
?<script> href.location="test.html"; </script> // 나쁜 표현
스크립트 블록 실행
// 올바르지 않은 방법
<div id="foo">Loading...</div>
<script type="text/javascript">
document.getElementById("foo").innerHTML = "Done.";
</script>
// 올바른 방법
<body onload="doFinish()">
<div id="foo">Loading...</div>
<script type="text/javascript">
function doFinish()
{ var element = document.getElementById("foo"); element.innerHTML = "Done."; }
</script>
Strict 모드에서 document.write()
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...
<script>
document.write("<script>alert("Hello")</script>")
</script>
Strict 모드에서는 Mozilla의 렌더링 엔진이 이를 허용 하지 않게 때문에 아래와 같이 표현
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
...
<script>
document.write("<script>alert("Hello")</" + "script>")
</script>
외부 객체 이용 방법
올바른 {+}OBJECT{+}{}{+}의 사용 방법+
<embed>와 <applet>은 지금까지 널리 쓰이긴 하였으나, HTML4.01에서 권고하지 않는방법으로 되어 될 수 있으면 사용하지 않는 것이 좋다
자바 애플릿을 불러올 경우에도 object 태그를 사용해야 하며, 아래와 같은 예제를 사용하여 불러온다.
<object classid="java:NervousText.class" width="534" height="50">
<param name="text" value="Java 2 SDK, Standard Edition v1.4">
<p>You need the Java Plugin. Get it from
<a href="http://java.sun.com/products/plugin/index.html" >here.</a>></p>
</object>
기술적인 호환성 때문에 제일 중요한 목표인 응용프로그램 실행에는 문제가 있다.
이를 해결하기 위해서는 ActiveX 개발자가 NSPlugin API를 참조하여 같은 기능의 Plugin을 개발해 줄 필요가 있다.
ActiveX와 대안 Plugin 기술
액티브X를 우리 나라에서 급속도로 쓸 수 밖에 없었던 이유가 몇 가지가 있다.
브라우저 내장 기술
Ajax
Ajax(Asynchronous JavaScript and XML)는 대화식 웹 어플리케이션의 제작을 위해 아래와 같은 조합을 이용하는 웹 개발 기법이다
DHTML이나 LAMP와 같이 Ajax는 자체가 하나의 특정한 기술을 말하는 것이 아니며, 함께 사용하는 기술의 묶음을 지칭하는 용어이다.
Ajax 어플리케이션은 필요한 데이터만을 주도록 웹 서버에 요청할 수 있다.
보통SOAP나 XML 기반의 웹 서비스 언어를 사용하며, 웹 서버의 응답을 처리하기 위해 클라이언트 쪽에서 자바스크립트를 쓴다.
Canvas
Canvas는 모질라 게코 렌더링 엔진에 HTML 엘리먼트로 추가된 기능이다.
모질라 캔버스 구현은 크로스 플랫폼 Cairo 벡터 그래픽 라이브러리를 이용한다.